package com.code2roc.fastboot.file;

import com.code2roc.fastboot.framework.config.SystemConfig;
import com.code2roc.fastboot.framework.file.FileStoargeProperty;
import com.code2roc.fastboot.framework.file.IFileOperate;
import com.code2roc.fastboot.framework.util.BeanUtil;
import com.code2roc.fastboot.framework.util.ConvertOp;
import com.code2roc.fastboot.framework.util.FileUtil;
import com.code2roc.fastboot.framework.util.StringUtil;
import io.minio.*;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MinioFileOperate implements IFileOperate {
    private MinioFileStoargeProperty property;
    private Map<String, String> contentType = new HashMap<>();
    private final Object LOCK = new Object();

    public MinioFileOperate(MinioFileStoargeProperty property) {
        this.property = property;
    }

    @Override
    public void storageFile(String bucketName, String key, byte[] bytes) throws Exception {
        storageFile(bucketName, key, ConvertOp.convertByteToStream(bytes));
    }

    @Override
    public void storageFile(String bucketName, String key, InputStream inputStream) throws Exception {
        MinioClient minioClient = getClient(bucketName);
        PutObjectOptions option = new PutObjectOptions(inputStream.available(), -1);
        String[] keyList = key.split("\\.");
        String type = keyList[keyList.length - 1];
        String fileContentType = getFileContentType("." + type);
        option.setContentType(fileContentType);
        minioClient.putObject(bucketName, key, inputStream, option);
    }

    @Override
    public void storageFileByChunk(String bucketName, String key, InputStream inputStream, String fileMD5, int chunkCount, int chunkIndex, int chunkSize) throws Exception {
        SystemConfig systemConfig = BeanUtil.getBean(SystemConfig.class);

        //检查分片
        boolean existChunk = false;
        String chunkFileFolderPath = systemConfig.getTemplatePath() + "attachchunfiles/" + fileMD5 + "/";
        FileUtil.initfloderPath(chunkFileFolderPath);
        String chunkFilePath = chunkFileFolderPath + fileMD5 + "-" + chunkIndex + ".temp";
        File chunkFile = new File(chunkFilePath);
        if (chunkFile.exists()) {
            existChunk = true;
        }
        //保存分片
        if (!existChunk) {
            String chunkeKey = "chunk/" + fileMD5 + "/" + fileMD5 + "-" + chunkIndex;
            storageFile(bucketName, chunkeKey, inputStream);
            chunkFile.createNewFile();
        }

        //合并分片
        if (chunkIndex == chunkCount - 1) {
            MinioClient minioClient = getClient(bucketName);
            String merageFilePath = chunkFileFolderPath + fileMD5 + ".temp";
            File merageFile = new File(merageFilePath);
            String chunkTag = "chunk/" + fileMD5 + "/" + fileMD5;
            if (!merageFile.exists()) {
                List<ComposeSource> sourceObjectList = new ArrayList<ComposeSource>();
                for (int i = 0; i < chunkCount; i++) {
                    ComposeSource composeSource = ComposeSource.builder().bucket(bucketName).object(chunkTag + "-" + i).build();
                    sourceObjectList.add(composeSource);
                }
                minioClient.composeObject(ComposeObjectArgs.builder().bucket(bucketName).object(chunkTag).sources(sourceObjectList).build());
                merageFile.createNewFile();
            }
            minioClient.copyObject(
                    CopyObjectArgs.builder()
                            .bucket(bucketName)
                            .object(key)
                            .source(
                                    CopySource.builder()
                                            .bucket(bucketName)
                                            .object(chunkTag)
                                            .build())
                            .build());
        }
    }

    @Override
    public byte[] getFileBytes(String bucketName, String key) throws Exception {
        MinioClient minioClient = getClient(bucketName);
        InputStream inputStream = minioClient.getObject(bucketName, key);
        return ConvertOp.convertStreamToByte(inputStream);
    }

    @Override
    public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) throws Exception {
        MinioClient minioClient = getClient(newBucketName);
        minioClient.copyObject(
                CopyObjectArgs.builder()
                        .bucket(originBucketName)
                        .object(originFileKey)
                        .source(
                                CopySource.builder()
                                        .bucket(newBucketName)
                                        .object(newFileKey)
                                        .build())
                        .build());
    }

    @Override
    public String getFileUrl(String bucketName, String key) throws Exception {
        MinioClient minioClient = getClient(bucketName);
        return minioClient.presignedGetObject(bucketName, key);
    }

    @Override
    public void deleteFile(String bucketName, String key) throws Exception {
        MinioClient minioClient = getClient(bucketName);
        minioClient.removeObject(bucketName, key);
    }

    @Override
    public String getFileSize(String bucketName, String key) throws Exception {
        MinioClient minioClient = getClient(bucketName);
        StatObjectArgs args = StatObjectArgs.builder().bucket(bucketName).object(key).build();
        ObjectStat stat = minioClient.statObject(args);
        return ConvertOp.convert2String(stat.length());
    }

    @Override
    public FileStoargeProperty getFileStoargeProperty() {
        return property;
    }


    private MinioClient getClient(String bucketName) {
        MinioClient minioClient = MinioClient.builder().
                endpoint(property.getEndpoint()).
                credentials(property.getAccessKey(), property.getSecrectKey()).build();
        try {
            boolean isExist = minioClient.bucketExists(bucketName);
            if (!isExist) {
                minioClient.makeBucket(bucketName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return minioClient;
    }

    private Map<String, String> getFileContentType() {
        synchronized (LOCK) {
            if (contentType.size() == 0) {
                contentType.put(".bmp", "application/x-bmp");
                contentType.put(".gif", "image/gif");
                contentType.put(".fax", "image/fax");
                contentType.put(".ico", "image/x-icon");
                contentType.put(".jfif", "image/jpeg");
                contentType.put(".jpe", "image/jpeg");
                contentType.put(".jpeg", "image/jpeg");
                contentType.put(".jpg", "image/jpeg");
                contentType.put(".png", "image/png");
                contentType.put(".rp", "image/vnd.rn-realpix");
                contentType.put(".tif", "image/tiff");
                contentType.put(".tiff", "image/tiff");
                contentType.put(".doc", "application/msword");
                contentType.put(".ppt", "application/x-ppt");
                contentType.put(".pdf", "application/pdf");
                contentType.put(".xls", "application/vnd.ms-excel");
                contentType.put(".txt", "text/plain");
                contentType.put(".java", "java/*");
                contentType.put(".html", "text/html");
                contentType.put(".avi", "video/avi");
                contentType.put(".movie", "video/x-sgi-movie");
                contentType.put(".mp4", "video/mpeg4");
                contentType.put(".mp3", "audio/mp3");
            }
        }
        return contentType;
    }

    private String getFileContentType(String fileSuffix) {
        String contentType = getFileContentType().get(fileSuffix);
        if (StringUtil.isEmpty(contentType)) {
            return "application/octet-stream";
        } else {
            return contentType;
        }
    }
}
